package drds.global_transaction.jdbc;


import drds.common.Author;
import drds.global_transaction.Authors;
import lombok.extern.slf4j.Slf4j;

import java.sql.Connection;
import java.sql.SQLException;

@Author(name = Authors.LI_YANG)
@Slf4j
public class ConnectionContext
{
    private final Connection connection;

    private boolean underlyingConCloseRequired = false;
    private boolean physicalConnectionReleased = false;
    private int physicalConnectionSharingCount = 0;


    public ConnectionContext(Connection connection)
    {
        this.connection = connection;
    }

    protected Connection getPhysicalConnection()
    {
        return this.connection;
    }

    public LogicalConnection getConnection() throws SQLException
    {
        if (this.physicalConnectionReleased)
        {
            throw new SQLException("ConnectionContext has already been closed!");
        }

        LogicalConnection logicalConnection = new LogicalConnection(this, this.connection);

        this.physicalConnectionSharingCount++;
        this.underlyingConCloseRequired = false;

        return logicalConnection;
    }

    public void closeLogicalConnection() throws SQLException
    {
        this.physicalConnectionSharingCount--;

        if (this.physicalConnectionSharingCount == 0)
        {
            this.underlyingConCloseRequired = true;
        }

    }

    private void releaseConnection()
    {
        if (this.physicalConnectionReleased == false)
        {
            try
            {
                this.connection.close();
            } catch (SQLException ex)
            {
                log.debug("Error occurred while closing connection!", ex);
            } catch (RuntimeException ex)
            {
                log.debug("Error occurred while closing connection!", ex);

            } finally
            {
                this.physicalConnectionReleased = true;
            }
        }
    }

    public void commitLocalTransaction() throws SQLException
    {
        try
        {
            this.connection.commit();
        } catch (SQLException ex)
        {
            throw ex;
        } catch (RuntimeException ex)
        {
            throw new SQLException(ex);
        }
    }

    public void rollbackLocalTransaction() throws SQLException
    {
        try
        {
            this.connection.rollback();
        } catch (SQLException ex)
        {
            throw ex;
        } catch (RuntimeException ex)
        {
            throw new SQLException(ex);
        }
    }

    public void closeQuietly()
    {
        try
        {
            this.close();
        } catch (Exception ex)
        {
            log.warn("Error occurred while closing physical connection.", ex);
        }
    }

    public void close() throws SQLException
    {
        if (this.underlyingConCloseRequired == false)
        {
            log.warn("Illegal state: there is at least one connection that is not closed!");
        }

        this.releaseConnection();
    }

}
